#ifndef __FRAME_H__
#define __FRAME_H__

/* STL */
#include <any>
#include <unordered_map>

/* Boost */
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>

namespace bi = boost::interprocess;

/* Violet */

/* Util */


namespace violet::frame {

class Serial {
  private:
    bi::vector<uint8_t, bi::allocator<uint8_t, bi::managed_shared_memory::segment_manager>> value_;

  public:
    Serial(const bi::allocator<uint8_t, bi::managed_shared_memory::segment_manager>& uint8_alloc)
            : value_(uint8_alloc) {}
    template <typename _VecType>
    Serial(const _VecType&                                                           serial,
           const bi::allocator<uint8_t, bi::managed_shared_memory::segment_manager>& uint8_alloc)
            : value_(uint8_alloc) {
        value_.clear();
        for (const auto& s : serial) value_.emplace_back(s);
    }

    auto Value() -> bi::vector<uint8_t, bi::allocator<uint8_t, bi::managed_shared_memory::segment_manager>>& {
        return value_;
    }
};

/* _Frame，一个数据中心，用以保存所有 viodef 对象 uint8_t 类型的序列化数据 */
class _Frame {
  private:
    bi::managed_shared_memory segment_;                    // construct with Frame instance
                                                           /* save the serial name */
    std::unordered_map<uint64_t, std::string> name_of_id_; // name of id

    /* main data constructed by boost::interprocess::map */
    bi::offset_ptr<
        bi::map</* key */ uint64_t,
                /* value */ Serial,
                /* compare algo */ std::less<uint64_t>,
                /* allocator of this map */
                bi::allocator<std::pair<const uint64_t, Serial>, bi::managed_shared_memory::segment_manager>>>
        data_;

  private:
    _Frame()
            : segment_(bi::managed_shared_memory{bi::open_or_create, "__violet_frame_shared_memory__", 1000000})
            , data_(segment_.construct<bi::map<
                        uint64_t, Serial, std::less<uint64_t>,
                        bi::allocator<std::pair<const uint64_t, Serial>, bi::managed_shared_memory::segment_manager>>>(
                  "__violet_frame_shared_memory_data__")(std::less<uint64_t>(), segment_.get_segment_manager())) {}
    ~_Frame() {
        bi::shared_memory_object::remove("__violet_frame_shared_memory__");
    }
    _Frame(const _Frame&) {}
    auto operator=(const _Frame&) -> _Frame& {
        return *this;
    }

  public:
    static auto GetInstance() -> _Frame& {
        static auto self = _Frame{};
        return self;
    }

    auto GetSerialMap() -> bi::offset_ptr<
        bi::map<uint64_t, Serial, std::less<uint64_t>,
                bi::allocator<std::pair<const uint64_t, Serial>, bi::managed_shared_memory::segment_manager>>> {
        return data_;
    }

    auto GetName(uint64_t id) -> std::string& {
        return name_of_id_.at(id);
    }

    auto GetSerial(uint64_t id) -> Serial& {
        return data_->at(id);
    }

    void AddSerialEmpty(uint64_t id, const std::string& name) {
        auto serial_constructed = segment_.construct<Serial>(
            (std::string{"__violet_frame_shared_memory_data_"} + std::to_string(id) + "__").c_str())(
            segment_.get_segment_manager());
        name_of_id_.insert_or_assign(id, name);
        data_->insert_or_assign(id, *serial_constructed);
    }

    template <typename _VecType>
    void AddSerialByVec(uint64_t id, const std::string& name, _VecType vec) {
        auto serial_constructed = segment_.construct<Serial>(
            (std::string{"__violet_frame_shared_memory_data_"} + std::to_string(id) + "__").c_str())(
            vec, segment_.get_segment_manager());
        name_of_id_.insert_or_assign(id, name);
        data_->insert_or_assign(id, *serial_constructed);
    }
};

#define Frame _Frame::GetInstance()

} // namespace violet::frame


#endif // __FRAME_H__